package com.nys.conci.base.utilitario;

import com.nys.conci.base.excepcion.ExcepcionServicio;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import sun.misc.BASE64Encoder;

/**
 * Clase utilitaria con metodos de encriptacion. Incluye metodos de encriptacion
 * para MD5 y SHA256. Esta clase, es programada con el patron Singleton, para
 * tener una unica instancia en memoria.
 * 
 * @author Huevo
 */
public class EncriptaUtil {

    /**
     * Instancia unica de EncriptaUtil
     */
    private static EncriptaUtil instancia;

    /**
     * Enumera con el listado de distintos algoritmos a los cuales puede
     * encriptar la clase utilitaria EncriptaUtil.
     */
    public enum Algoritmo {
        SHA256,
        MD5;
    }

    /**
     * Constructor privado
     */
    private EncriptaUtil() {
    }

    /**
     * Metodo encargado de crear la instancia unica de la clase.
     */
    private synchronized static void crearInstancia() {
        if (instancia == null) {
            instancia = new EncriptaUtil();
        }
    }

    /**
     * Metodo encargado de retornar una instancia del objeto. Esta instancia
     * es unica, para la aplicacion.
     * @return Objeto
     */
    public static EncriptaUtil getInstancia() {
        if (instancia == null) {
            crearInstancia();
        }
        return instancia;
    }

    /**
     * Metodo encargardo de encriptar el valor indicado, y transformarlo segun
     * el algoritmo indicado
     * @param valor Valor a encriptar
     * @param alg Algoritmo de encriptacion
     * @return Valor encriptado
     */
    public String encriptar(String valor, Algoritmo alg){
        if(Algoritmo.SHA256.equals(alg)){
            return sha256(valor);
        }else if(Algoritmo.MD5.equals(alg)){
            return md5(valor);
        }
        return "";
    }
    
    /**
     * Codifica el texto recibido como parametro en SHA256.
     * @param texto Texto a encriptar
     * @return Texto encriptado
     */
    private String sha256(String texto) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA-256"); //paso 1
        } catch (NoSuchAlgorithmException e) {
            throw new ExcepcionServicio("Error encriptando la contraseña", e, this.getClass());
        } //catch
        try {
            md.update(texto.getBytes("UTF-8")); //paso 2
        } catch (UnsupportedEncodingException e) {
            throw new ExcepcionServicio("Error encriptando la contraseña", e, this.getClass());
        } //catch
        byte raw[] = md.digest(); //paso 3
        String hash = (new BASE64Encoder()).encode(raw); //paso 4
        return hash; //paso 5

        //return texto;
    } //encriptar
    
    /**
     * Codifica el texto recibido como parametro en MD5.
     * @param texto Texto a encriptar
     * @return Texto encriptado
     */
    private String md5(String valor){
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] b = md.digest(valor.getBytes());

            int size = b.length;
            StringBuilder h = new StringBuilder(size);
            for (int i = 0; i < size; i++) {
                int u = b[i] & 255;
                if (u < 16) {
                    h.append("0").append(Integer.toHexString(u));
                } else {
                    h.append(Integer.toHexString(u));
                }
            }
            return h.toString();
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(EncriptaUtil.class.getName()).log(Level.SEVERE, null, ex);
        }
        return "";
    }
}
